package mcom.xmks.bluetooth.mesh;

import android.content.Intent;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.EditText;

import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;

import java.util.ArrayList;
import java.util.List;

import cn.wch.meshlib.core.MeshServer;
import cn.wch.meshlib.frame.ack.AckFrame;
import cn.wch.meshlib.frame.ack.AckType;
import io.reactivex.Emitter;
import mcom.xmks.bluetooth.mesh.base.NodeBaseActivity;
import mcom.xmks.bluetooth.mesh.constant.IntentConstant;
import mcom.xmks.bluetooth.mesh.core.DataModel;
import mcom.xmks.bluetooth.mesh.dialog.DialogUtil;
import mcom.xmks.bluetooth.mesh.storage.NodeItem;
import mcom.xmks.bluetooth.mesh.storage.StorageUtil;
import mcom.xmks.bluetooth.mesh.utils.ConvertUtil;
import mcom.xmks.bluetooth.mesh.utils.LogTool;

public class ConfigNetActivity extends NodeBaseActivity {
    private EditText tvInputKey,tvInputAddress,tvInputName;
    private Button btnConfig;
    private Intent intent=null;
    private String macAddress=null;
    /**密钥头信息*/
    private static final String KEY_HEAD="蓝牙mesh";
    @Override
    protected void setView() {
        this.setContentView(R.layout.activity_config_net);
        tvInputKey=this.findViewById(R.id.tvInputKey);
        tvInputAddress=this.findViewById(R.id.tvInputAddress);
        tvInputName=this.findViewById(R.id.tvInputName);
        btnConfig=this.findViewById(R.id.btnConfig);

        ActionBar actionBar = getSupportActionBar();
        if(actionBar!=null){
            actionBar.setTitle("配置节点");
            actionBar.setHomeButtonEnabled(true);  //启用返回按钮
            actionBar.setDisplayHomeAsUpEnabled(true); //显示返回按钮
        }
    }
    @Override
    protected void initWidget() {
        intent=this.getIntent();
        if(intent.hasExtra(IntentConstant.SCAN_SELECT_DEVICE)) {
            macAddress = intent.getStringExtra(IntentConstant.SCAN_SELECT_DEVICE);
        }
        btnConfig.setOnClickListener(v->{
            startConfigNode();//配置节点
        });
        String configKey= StorageUtil.getConfigKey();//从数据表单中读取用户配置密钥（不包含密钥头信息）
        tvInputKey.setText(configKey);
        connect();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main,menu);
        menu.findItem(R.id.connect).setVisible(!isConnected);
        menu.findItem(R.id.disconnect).setVisible(isConnected);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case R.id.connect:
                connect();
                break;
            case R.id.disconnect:
                disconnectBLE(false);
                break;
            case android.R.id.home:
                onBackPressed();
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onBackPressed() {
        if(isConnected){
            DialogUtil.getInstance().showSimpleDialog(this, "需要先断开与当前蓝牙的连接，是否断开?",
                    "断开", "取消", new DialogUtil.IResult() {
                        @Override
                        public void onContinue() {
                            disconnectBLE(false);
                        }
                        @Override
                        public void onCancel() {
                        }
                    });
        }else{
            super.onBackPressed();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        LogTool.d("ConfigNetActivity destroy");
    }

    private void connect(){
        if(macAddress==null){
            showToast("mac地址为空");
        }else {
            connectBLE(macAddress);
        }
    }
    /**
     * 开始配置节点
     */
    private void startConfigNode(){
        if(!isBLEConnected()){
            showToast("尚未连接到蓝牙设备");
            return;
        }
        String userKey = tvInputKey.getText().toString();
        String key =getKey(userKey); //tvInputKey.getText().toString();
        String address = tvInputAddress.getText().toString();
        String name =  tvInputName.getText().toString();
        //check key
        if(key==null){
            showToast("输入的密钥非法或为空");
            return;
        }
        if(!key.matches("([0-9|a-f|A-F]{2}){16}")){
            showToast("密钥必须为合法的32字节");
            return;
        }
        //check address
        if(!address.matches("([0-9|a-f|A-F]{2}){2}")){
            showToast("地址必须为合法的2字节");
            return;
        }
        //check name
        if(name.isEmpty()){
            showToast("节点名称为空");
            return;
        }
        //parse key and address
        byte[] keyData = ConvertUtil.fromHexString2ByteArray(key);
        int addressData = Integer.parseInt(address,16);
        if((addressData)>0x00007fff){
            showToast("节点地址不大于7FFF");
            return;
        }
        if(StorageUtil.checkNodeHasExist(addressData)){
            //节点已经存在
            showToast("节点地址已经存在");
            return;
        }
        int ivIndex = StorageUtil.getIvIndex();
        int flag = StorageUtil.getFlag();
        List<AckFrame> commandLists=new ArrayList<>();
        try {
            commandLists.add(MeshServer.getInstance().setNetworkInfo(ivIndex, (byte) flag));
            commandLists.add(MeshServer.getInstance().meshProvision(keyData,addressData));

            DataModel.getInstance().rxjavaExecuteAny(this, "正在配置节点", commandLists,
                    (DataModel.CallbackShouldContinue<AckFrame>) frame -> {
                        if(frame.getAckType()==AckType.PROVISION_INFO){
                            return frame.getStatusCode()==0;
                        }
                        return true;
                    }, new Emitter<>() {
                        @Override
                        public void onNext(AckFrame value) {
                            if(value.getAckType()==AckType.PROVISION){
                                String addressString = ConvertUtil.getNodeHexString(value.getNetAddress());
                                showToast("设置节点"+addressString+(value.getStatusCode()==0?"成功":"失败"));
                                if(value.getStatusCode()==0 && value.getNetAddress()==addressData){;
                                    saveToLocalAndExit(userKey,addressData,name);
                                }
                            }else if(value.getAckType()==AckType.PROVISION_INFO){
                                showToast("设置网络信息"+(value.getStatusCode()==0?"成功":"失败"));
                            } else{
                                showToast("error ack");
                            }
                        }
                        @Override
                        public void onError(Throwable e) {
                            LogTool.d(e.getMessage());
                            showToast(e.getMessage());
                        }
                        @Override
                        public void onComplete() {
                        }
                    });
        } catch (Exception e) {
            LogTool.d(e.getMessage());
            showToast(e.getMessage());
        }
    }

    /**
     * 保存节点信息到本地并退出
     * @param key 密钥（用户段）
     * @param netAddress 节点地址
     * @param name 节点名称
     */
    private void saveToLocalAndExit(String key,int netAddress,String name){
        //when config success,save message
        StorageUtil.putNode(new NodeItem(name,netAddress,false));
        //save key
        StorageUtil.setConfigKey(key);
        //disconnect
        disconnectBLE(true);
        //leave
        //startActivity(new Intent(this,MainActivity.class));
        setResult(RESULT_OK,intent);
        finish();
    }

    /**
     * 获取密钥16进制字符串
     * @param userKey 用户密钥字符串（字母、数字或英文特殊字符）
     * @return 成功包含密钥头部信息的32位密钥，失败{@code null}
     */
    private String getKey(String userKey){
        if(userKey.length()==6){   //用户输入的密钥长度必须是6给字符
            if(checkKey(userKey)){
                return ConvertUtil.str2HexStr(KEY_HEAD+userKey);
            }
        }
        return null;
    }

    /**
     * 检查用户密钥是否位合法的字符串
     * @param userKey
     * @return
     */
    private  boolean checkKey(String userKey){
        //正则式检查key字符串是否在英文，数字或特殊字符范围
        String regex="^[a-zA-Z0-9_,.?/~`@#$%^&*()\\-\\+\\=<>{}|\\[\\]\\\\:;'\"\"]*$";
        return userKey.matches(regex);
    }
}